package com.geekhalo.demo.mq.event.fix;

import com.geekhalo.demo.mq.event.BaseController;
import com.geekhalo.demo.mq.event.Order;
import com.geekhalo.lego.core.web.RestResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.concurrent.*;


@RestController
@RequestMapping("mq/event/fix")
@Slf4j
public class SMSTimeoutThreadPoolController extends BaseController {
    // 定义独立的线程
    private ExecutorService executorService;

    @PostConstruct
    public void init() {
        // 核心线程数 为 CPU 数量
        int coreThreads = Runtime.getRuntime().availableProcessors();
        // 【控制资源】最大线程数 为 核心线程数 的 5 倍
        int maxThreads = coreThreads * 5;
        // 【控制资源】队列长度为 1024
        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(1024);
        // 【避免阻塞】线程 和 队列 资源耗尽后，直接抛弃最老的任务，避免造成阻塞
        RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.DiscardOldestPolicy();
        // 自定义线程工厂
        BasicThreadFactory threadFactory = new BasicThreadFactory.Builder()
                .namingPattern("SMS-Send-Thread-%d")
                .daemon(true)
                .uncaughtExceptionHandler((t, e) -> log.error("Failed to run task", e))
                .build();
        // 自定义线程池
        this.executorService = new ThreadPoolExecutor(coreThreads, maxThreads,
                5, TimeUnit.MINUTES,
                queue,
                threadFactory,
                rejectedExecutionHandler
                );
    }

    @PostMapping("paySuccessUseThreadPool")
    @Transactional
    public RestResult<Boolean> paySuccess(@RequestParam Long orderId, @RequestParam String token){
        // 验证 token，保障有效性
        checkToke(token);

        // 加载订单信息
        Order order = findById(orderId);
        if (order == null){
            return RestResult.success(false);
        }
        // 支付成功，更新订单状态
        order.paySuccess();
        // 将变更更新到数据库
        updateOrder(order);

        // 【核心改动点】将任务提交到独立的线程池，避免受影响
        // 避免对主流程的影响
        this.executorService.execute(() -> sendSMSNotice(order));

        return RestResult.success(true);
    }
}
